//
// Created by aruba on 2020/10/21.
//

#include "_ffmpeg_audio_decoder.h"

/**
   * 播放器会不断调用此函数，我们需要在此回调中不断给缓冲区填充数据
   * @param bufferQueueItf 
   * @param pContext 
   */
void playerCallback(SLAndroidSimpleBufferQueueItf bq, void *pContext) {
//    __android_log_print(ANDROID_LOG_ERROR, LOG_TAG_FFMPEG_AUDIO_DECODER,
//                        "准备播放");
    //准备播放
    FFmpegAudioDecoder *audioDecoder = (FFmpegAudioDecoder *) (pContext);

//    __android_log_print(ANDROID_LOG_ERROR, LOG_TAG_FFMPEG_AUDIO_DECODER,
//                        "helper.playState");
    if (audioDecoder->helper.playState == SL_PLAYSTATE_PLAYING) {
//        __android_log_print(ANDROID_LOG_ERROR, LOG_TAG_FFMPEG_AUDIO_DECODER,
//                            "开始解码");
        //解码
        int picture_ptr = 0;

        double clockTemp = 0;
        while (audioDecoder->isPlay) {
//            __android_log_print(ANDROID_LOG_ERROR, LOG_TAG_FFMPEG_AUDIO_DECODER,
//                                "准备取出一个packet");
            audioDecoder->get(audioDecoder->avPacket);//从队列获取压缩数据

            //计算当前帧的播放时间
            if (audioDecoder->avPacket->pts != AV_NOPTS_VALUE) {
                clockTemp = av_q2d(audioDecoder->time_base) * audioDecoder->avPacket->pts;
            }

//            __android_log_print(ANDROID_LOG_ERROR, LOG_TAG_FFMPEG_AUDIO_DECODER,
//                                "取出一个packet");
            int ret = avcodec_decode_audio4(audioDecoder->codecContext, audioDecoder->picture,
                                            &picture_ptr,
                                            audioDecoder->avPacket);
            if (ret < 0) {
                __android_log_print(ANDROID_LOG_ERROR, LOG_TAG_FFMPEG_AUDIO_DECODER,
                                    "Error while decoding. len = %d",
                                    ret);
            }

            if (picture_ptr) {
                //转码
                swr_convert(audioDecoder->swrContext, &audioDecoder->out, audioDecoder->out_size,
                            (const uint8_t **) (audioDecoder->picture->data),
                            audioDecoder->picture->nb_samples);

                //缓冲区真实大小
                audioDecoder->buff_size = av_samples_get_buffer_size(NULL,
                                                                     audioDecoder->channel_count,
                                                                     audioDecoder->picture->nb_samples,
                                                                     AV_SAMPLE_FMT_S16, 1);
                break;
            }
        }

        //修正实际播放时间
        if (audioDecoder->buff_size > 0) {
            //一秒中的数据量:单通道数据量*声道数
            double data_size = audioDecoder->out_size * audioDecoder->channel_count;
            //当前packet中包含了多帧的数据量
            double time = audioDecoder->buff_size / data_size;
//            __android_log_print(ANDROID_LOG_ERROR, LOG_TAG_FFMPEG_AUDIO_DECODER,
//                                "多帧的数据长度%d  播放多帧需要的时间%f ", audioDecoder->buff_size, time);
            audioDecoder->clock = clockTemp + time;
//            __android_log_print(ANDROID_LOG_ERROR, LOG_TAG_FFMPEG_AUDIO_DECODER,
//                                "实际播放时间%f", audioDecoder->clock);
        }

        //播放
        if (audioDecoder->out != NULL && audioDecoder->buff_size != 0 && audioDecoder->isPlay) {
            (*bq)->Enqueue(bq, audioDecoder->out, (SLuint32) (audioDecoder->buff_size));
        }
//        __android_log_print(ANDROID_LOG_ERROR, LOG_TAG_FFMPEG_AUDIO_DECODER,
//                            "播放%d", picture_ptr);
    } else if (audioDecoder->helper.playState == SL_PLAYSTATE_STOPPED || !audioDecoder->isPlay) {
        __android_log_print(ANDROID_LOG_ERROR, LOG_TAG_FFMPEG_AUDIO_DECODER,
                            "停止播放");
        audioDecoder->release();
        audioDecoder->helper.~OpenslHelper();
        delete (audioDecoder);
    }
}

//解码音频数据线程
void *decodeAudio(void *arg) {
    FFmpegAudioDecoder *audioDecoder = (FFmpegAudioDecoder *) (arg);

    //初始化opensl
    SLresult result = audioDecoder->helper.createEngine();
    if (!audioDecoder->helper.isSuccess(result)) {
        __android_log_print(ANDROID_LOG_ERROR, LOG_TAG_FFMPEG_AUDIO_DECODER, "createEngine失败");
        audioDecoder->isPlay = false;
        pthread_exit(0);
    }
    result = audioDecoder->helper.createMix();
    if (!audioDecoder->helper.isSuccess(result)) {
        __android_log_print(ANDROID_LOG_ERROR, LOG_TAG_FFMPEG_AUDIO_DECODER, "createMix失败");
        audioDecoder->isPlay = false;
        pthread_exit(0);
    }

    //创建播放器
    result = audioDecoder->helper.createPlayer(2, SL_SAMPLINGRATE_44_1, SL_PCMSAMPLEFORMAT_FIXED_16,
                                               SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT);
    if (!audioDecoder->helper.isSuccess(result)) {
        __android_log_print(ANDROID_LOG_ERROR, LOG_TAG_FFMPEG_AUDIO_DECODER, "createPlayer失败");
        audioDecoder->isPlay = false;
        pthread_exit(0);
    }

    //初始化解码参数
    audioDecoder->avPacket = (AVPacket *) (av_malloc(sizeof(AVPacket)));
    av_init_packet(audioDecoder->avPacket);
    //存放解压数据
    audioDecoder->picture = av_frame_alloc();
    //音频转码组件上下文
    audioDecoder->swrContext = swr_alloc();
    //AV_CH_LAYOUT_STEREO:双声道  AV_SAMPLE_FMT_S16:量化格式 16位 codecContext->sample_rate:采样率 Hz
    swr_alloc_set_opts(audioDecoder->swrContext, AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_S16,
                       audioDecoder->codecContext->sample_rate,//输出采样率和输入采样率应相同
                       audioDecoder->codecContext->channel_layout,
                       audioDecoder->codecContext->sample_fmt,
                       audioDecoder->codecContext->sample_rate, 0, NULL
    );
    swr_init(audioDecoder->swrContext);

    //原音频通道数
    audioDecoder->channel_count = av_get_channel_layout_nb_channels(
            AV_CH_LAYOUT_STEREO);
    //单通道最大存放转码数据 所占字节 = 采样率*量化格式 / 8
    audioDecoder->out_size = 44100 * 16 / 8;
    audioDecoder->out = (uint8_t *) (av_malloc(audioDecoder->out_size));

    //开始真正的播放音频
    audioDecoder->helper.registerCallback(playerCallback, audioDecoder);
    audioDecoder->helper.play();
    playerCallback(audioDecoder->helper.bufferQueueItf, audioDecoder);

    //退出线程，交给opensl调用回调
    pthread_exit(0);
}

//开始播放
void FFmpegAudioDecoder::play() {
    //开启线程
    startPlay(decodeAudio, this);
}

//停止播放
void FFmpegAudioDecoder::stop() {
    //调用基类方法
    FFmpegDecoder::stop();
    //停止播放
    helper.stop();
    helper.~OpenslHelper();
    release();
    delete (this);
}

//释放资源
void FFmpegAudioDecoder::release() {
    __android_log_print(ANDROID_LOG_ERROR, LOG_TAG_FFMPEG_AUDIO_DECODER,
                        "释放音频资源");
    //释放资源
    av_packet_unref(avPacket);
    av_free_packet(avPacket);
    av_free(out);
    swr_free(&swrContext);
    av_frame_free(&picture);
    avcodec_close(codecContext);
}